home *** CD-ROM | disk | FTP | other *** search
- /*
- File: OHCIFWIMIsoch.c
-
- Contains: FireWire interface module isochronous software for OpenHCI 1394 cards.
-
- Version: 1.0
-
- Written by: Jay Lloyd
-
- Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved.
-
- File Ownership:
-
- DRI: Jay Lloyd
-
- Other Contact: Eric Anderson
-
- Technology: FireWire
-
- Writers:
-
- (jkl) Jay Lloyd
-
- Change History (most recent first):
-
- <FW7> 9/25/98 jkl Added separate end of DCL label handling for isoch receive and
- transmit. This should allow DV transmit and the CCM camera to
- work at the same time. Changed skip address on isoch transmit to
- redo the same descriptor instead of going to the next one to
- make it act more Lynx like.
- <FW6> 8/26/98 jkl Moved the dummyQuad used in isoch receive from fwim data to
- DMABuildState. Improved isoch transmit DCL compile by adding 'no
- packet for cycle' descriptors for the labels at the end. Still
- needs some work to keep transmit running.
- <FW5> 8/9/98 jkl Fixed a problem with packet size in isoch transfer.
- <FW4> 8/7/98 jkl Fixed UpdateDCLList functionality.
- <FW3> 8/6/98 jkl Fixed a problem in transmit deferred task where receive port was
- being used. Changed all DebugStr to FWDebugStr.
- <FW2> 8/5/98 jkl Cleaned up some more isoch transfers. Fixed a problem with null
- packet processing in DV output DCL.
- <FW1> 8/4/98 jkl first checked in
-
- */
-
- #include <DriverServices.h>
- #include <PCI.h>
- #include "FireWire.h"
- #include "OHCIFWIM.h"
-
- #include <stdio.h>
- extern char debugStr[256];
- static pascal void FWDebugStr(
- ConstStr255Param debuggerMsg);
- static pascal void FWDebugStr(
- ConstStr255Param debuggerMsg)
- {
- #ifdef FW_DEBUG_BUILD
- #if FW_DEBUG_BUILD
- DebugStr (debuggerMsg);
- #endif
- #endif
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Routines available to OHCIFWIM.c
- //
- OSStatus OHCIFWIMAllocateIsochPort(
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- OSStatus OHCIFWIMReleaseIsochPort (
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- OSStatus OHCIFWIMStartIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- OSStatus OHCIFWIMStopIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- void HandleIsochRxInterrupt(
- FWIMDataPtr pFWIMData);
-
- void HandleIsochTxInterrupt(
- FWIMDataPtr pFWIMData);
-
- void IsochReceiveDeferredTask(
- void *p1,
- void *p2);
-
- void IsochTransmitDeferredTask(
- void *p1,
- void *p2);
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Private Routines
- //
- static Boolean IsCompilableDCLProgram(
- DCLProgramID dclProgramID);
-
- static OSStatus CompileDCLProgram(
- FWIMDataPtr pFWIMData,
- DCLProgramID dclProgramID,
- UInt32 dmaPortNum,
- UInt32 channelNum,
- UInt32 speed,
- Boolean talking);
-
- static OSStatus PrepareDCLProgramMemory(
- DCLCompilerEngineDataPtr pDCLCompilerEngineData,
- DCLCommandPtr dclList,
- UInt32 dclListLength);
-
- static OSStatus AllocateDMA(
- DMABuildStatePtr pDMABuildState,
- DMADescriptorPtr *ppDMA,
- PhysicalAddress *ppDMAPhys,
- UInt32 count);
-
- static OSStatus ReleaseIsochPort(
- FWIMDataPtr pFWIMData,
- IsochPortDataPtr pIsochPortData);
-
- static OSStatus DCLCompilerNotification(
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus DCLCompilerUpdateNotification (
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus DCLCompilerModifyNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus StartTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus StopTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus StartListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus StopListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus ReleaseDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus AddDCL (
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed);
-
- static void DeallocateDMAPools (
- DMAPoolDataPtr pDMAPoolDataList);
-
- static OSStatus AddReceivePacketStartDCL (
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static Boolean AddReceiveDCLInterrupt (
- DCLCommandPtr pDCLCommand,
- FWIMDataPtr pFWIMData,
- UInt32 portNum);
-
- static UInt32 DataMapToPhysical (
- DCLCompilerEngineDataPtr pDCLCompilerEngineData,
- Ptr pBuffer,
- UInt32 size,
- PhysicalMappingTablePtr returnTable);
-
- static OSStatus AddReceivePacketDCL (
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus AddTimeStampDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus AddSendPacketStartDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed);
-
- static Boolean AddTransmitDCLInterrupt (
- DCLCommandPtr pDCLCommand,
- FWIMDataPtr pFWIMData,
- UInt32 portNum);
-
- static OSStatus AddSendPacketWithHeaderStartDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed);
-
- static OSStatus AddSendPacketDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus AddCallProcDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus AddUpdateDCLListDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus AddJumpAddress(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus ProcessJumpDCL(
- DCLJumpPtr pDCLJump);
-
- static OSStatus ProcessLabelDCL(
- DMABuildStatePtr pDMABuildState,
- DCLLabelPtr pDCLLabel,
- Boolean talking);
-
- static OSStatus AddSetTagSyncBitsDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus UpdateDCLTimeStamp(
- DCLTimeStampPtr pDCLTimeStamp);
-
- static OSStatus UpdateDCLReceivePacketStart(
- DCLTransferPacketPtr pDCLTransferPacket);
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // OHCIFWIMAllocateIsochPort
- //
- // Allocate an isochronous port.
- //zzz must make sure that port is not already in use.
- //zzz should do more error checking.
- //zzz we may need to keep a list of isoch port data records.
- //
- // JKL *** all of this is hard coded to just use isoch context 0 for now
- //
-
- OSStatus OHCIFWIMAllocateIsochPort(
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- OHCIRegistersPtr pOHCIRegs;
- FWIMDataPtr pFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- IsochPortDataPtr pIsochPortData = nil;
- UInt32 dmaPortNum;
- OSStatus status = noErr;
- Boolean talking;
-
- // FWDebugStr ((ConstStr255Param) "\pOHCIFWIMAllocateIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &pFWIMAllocateIsochPortParams->fwimCommandParams;
- pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Set pending command.
- pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
- pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
-
- // Are we talking?
- talking = pFWIMAllocateIsochPortParams->talking;
-
- // Get dma channel number.
- if (talking)
- dmaPortNum = kIsochTransmitPort;
- else
- dmaPortNum = kIsochReceivePort;
-
- // Create an isoch port data record.
- pIsochPortData = (IsochPortDataPtr) PoolAllocateResident(sizeof(IsochPortData), true);
- if (pIsochPortData != nil)
- {
- pFWIMData->isochPortDataList[dmaPortNum] = pIsochPortData;
- pIsochPortData->originalDCLProgramID = pFWIMAllocateIsochPortParams->dclProgramID;
- pIsochPortData->translatedDCLProgramID = (DCLProgramID) kInvalidDCLProgramID;
- pIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
- pIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
- pIsochPortData->talking = talking;
- }
- else
- {
- status = memFullErr;
- }
-
- // Compile a DMA program from DCL program.
- if (status == noErr)
- {
- // Check if program must be translated.
- if (IsCompilableDCLProgram(pIsochPortData->originalDCLProgramID))
- {
- pIsochPortData->dclProgramID = pIsochPortData->originalDCLProgramID;
- }
- else
- {
- //zzz need to be able to deallocate this.
- status = FWTranslateDCLProgram(pIsochPortData->originalDCLProgramID,
- &(pIsochPortData->translatedDCLProgramID));
- if (status == noErr)
- pIsochPortData->dclProgramID = pIsochPortData->translatedDCLProgramID;
- }
-
- // Compile the DCL program.
- if (status == noErr)
- {
- status = CompileDCLProgram(pFWIMData,
- pIsochPortData->dclProgramID,
- dmaPortNum,
- pIsochPortData->channelNum,
- pIsochPortData->speed,
- talking);
- }
-
- // Set start, stop, and release procedures for DCL program.
- if (status == noErr)
- {
- if (talking)
- {
- FWSetDCLProgramStartProc(pIsochPortData->dclProgramID,
- StartTalkingDCLProgram);
- FWSetDCLProgramStopProc(pIsochPortData->dclProgramID,
- StopTalkingDCLProgram);
- FWSetDCLProgramReleaseProc(pIsochPortData->dclProgramID,
- ReleaseDCLProgram);
- }
- else
- {
- FWSetDCLProgramStartProc(pIsochPortData->dclProgramID,
- StartListeningDCLProgram);
- FWSetDCLProgramStopProc(pIsochPortData->dclProgramID,
- StopListeningDCLProgram);
- FWSetDCLProgramReleaseProc(pIsochPortData->dclProgramID,
- ReleaseDCLProgram);
- }
- }
- }
-
- // Set up appropriate DMA context.
- if (status == noErr)
- {
- if (talking)
- {
- // Quiet the DMA context.
- // JKL *** is this the right thing to do?
- pOHCIRegs->isochTxContext[kITContext0].controlClear = 0xffffffff;
- SynchronizeIO ();
- }
-
- // Set up context to receive on this port's channel.
- if (!talking)
- {
- IRDMAContextPtr pIRContext = &pOHCIRegs->isochRxContext[kIRContext0];
-
- // Quiet the DMA context.
- pIRContext->controlClear = 0xffffffff;
-
- // want packet per buffer and isoch headers
- pIRContext->controlSet = EndianSwapImm32Bit(kIRDMAIsochHeader);
-
- pIRContext->match = EndianSwapImm32Bit(kIRDMATag0 | kIRDMATag1 | kIRDMATag2 | kIRDMATag3 |
- pIsochPortData->channelNum);
- SynchronizeIO ();
- }
-
- // Set our data for port.
- pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData = (UInt32) pIsochPortData;
- }
-
- // Clean up on error.
- if (status != noErr)
- {
- if (pIsochPortData != nil)
- ReleaseIsochPort(pFWIMData, pIsochPortData);
- }
-
- // Complete FWIM command.
- pFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // OHCIFWIMReleaseIsochPort
- //
- // Release resources allocated for the given isochronous port.
- //
-
- OSStatus OHCIFWIMReleaseIsochPort(
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMDataPtr pFWIMData;
- IsochPortDataPtr pIsochPortData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &pFWIMReleaseIsochPortParams->fwimCommandParams;
- pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
- pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pIsochPortData = (IsochPortDataPtr)
- pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Release resources for isoch port.
- if (pIsochPortData != nil)
- status = ReleaseIsochPort(pFWIMData, pIsochPortData);
-
- // Complete FWIM command.
- pFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // OHCIFWIMStartIsochPort
- //
- // Start up the given isochronous port on the given sync event using the
- // given buffer.
- //
-
- OSStatus OHCIFWIMStartIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMDataPtr pFWIMData;
- IsochPortDataPtr pIsochPortData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &pFWIMIsochPortControlParams->fwimCommandParams;
- pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pIsochPortData = (IsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Start DCL program.
- if (status == noErr)
- status = FWStartDCLProgram(pIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // OHCIFWIMStopIsochPort
- //
- // Stop the given isochronous port on the given sync event.
- //
-
- OSStatus OHCIFWIMStopIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMDataPtr pFWIMData;
- IsochPortDataPtr pIsochPortData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &pFWIMIsochPortControlParams->fwimCommandParams;
- pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pIsochPortData = (IsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Stop DCL program.
- if (status == noErr)
- status = FWStopDCLProgram(pIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // IsCompilableDCLProgram
- //
- // Determine if the given DCL program is compilable.
- //zzz a table and range check may be faster.
- //zzz should do better checking.
- //zzz maybe we should make this determination in a first pass compilation.
- //
-
- static Boolean IsCompilableDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCommandPtr pDCLCommand;
- Boolean isCompilable = true;
- UInt32 opcode;
- OSStatus status = noErr;
-
- // Get first DCL in program.
- status = FWGetDCLProgramStart(dclProgramID, &pDCLCommand);
- if (status != noErr)
- isCompilable = false;
-
- // Check each DCL in program.
- while (isCompilable && (pDCLCommand != nil))
- {
- opcode = pDCLCommand->opcode;
- opcode &= ~kFWDCLOpDynamicFlag; // We can compile dynamic opcodes.
- switch (opcode)
- {
- case kDCLReceivePacketStartOp :
- break;
-
- case kDCLReceivePacketOp :
- break;
-
- case kDCLSendPacketStartOp :
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- break;
-
- case kDCLSendPacketOp :
- break;
-
- case kDCLCallProcOp :
- break;
-
- case kDCLJumpOp :
- break;
-
- case kDCLLabelOp :
- break;
-
- case kDCLSetTagSyncBitsOp :
- break;
-
- case kDCLUpdateDCLListOp :
- break;
-
- case kDCLTimeStampOp :
- break;
-
- default :
- isCompilable = false;
- break;
- }
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
- return isCompilable;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // CompileDCLProgram
- //
- // Compile the given DCL program into a DMA program.
- //zzz need to set proper speed.
- //
-
- static OSStatus CompileDCLProgram(
- FWIMDataPtr pFWIMData,
- DCLProgramID dclProgramID,
- UInt32 dmaPortNum,
- UInt32 channelNum,
- UInt32 speed,
- Boolean talking)
- {
- DMABuildStatePtr pDMABuildState = nil;
- DCLCompilerEngineDataPtr pDCLCompilerEngineData = nil;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCommandPtr pDCLCommand,
- dclList;
- UInt32 startEvent,
- startEventState,
- startEventStateMask;
- UInt32 dclListLength;
- OSStatus status = noErr;
-
- // Create DCL engine data record.
- pDCLCompilerEngineData =
- (DCLCompilerEngineDataPtr) PoolAllocateResident(sizeof(DCLCompilerEngineData), true);
- if (pDCLCompilerEngineData == nil)
- status = memFullErr;
- else
- pDCLCompilerEngineData->pFWIMData = pFWIMData;
-
- // Initialize interrupt list.
- if (status == noErr)
- pFWIMData->numDCLInterrupts[dmaPortNum] = 0;
-
- // Set compiler notification proc.
- if (status == noErr)
- status = FWSetDCLProgramCompilerNotificationProc(dclProgramID, DCLCompilerNotification);
-
- // Get DCL list from program.
- if (status == noErr)
- status = FWGetDCLProgramStart(dclProgramID, &dclList);
-
- // Count the DCLs.
- if (status == noErr)
- {
- pDCLCommand = dclList;
- dclListLength = 0;
- while (pDCLCommand != nil)
- {
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- dclListLength++;
- }
- }
-
- // Allocate compiler data structures for all DCLs
- if (status == noErr)
- {
- pDCLCompilerDCLData = PoolAllocateResident(dclListLength * sizeof(DCLCompilerDCLData), true);
- if (pDCLCompilerDCLData == nil)
- {
- status = memFullErr;
- }
- else
- {
- pDCLCompilerEngineData->pDCLCompilerDCLData = pDCLCompilerDCLData;
- // Assign compiler data storage to each DCL
- pDCLCommand = dclList;
- while (pDCLCommand != nil)
- {
- pDCLCommand->compilerData = (UInt32) pDCLCompilerDCLData;
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- pDCLCompilerDCLData++;
- }
- }
- }
-
- // The plan is to, before compiling, scan the program to locate all data
- // buffers. Then we'll prepare VM mappings for them all at once. Then
- // during compilation we can look up the logical->physical mappings.
- //
- // A complication is that we may receive notification that a running
- // program has had its buffers changed. We get a list of changes. In
- // that case we need to prepare the new buffers for DMA and change the
- // pointers in the descriptors, possibly expanding them if there are more
- // page crossings than before. (or maybe not)
- //
- // When we update buffers, some may be unchanged, so we can't clear the
- // original PrepareMemoryForIO. Buffers can be updated repeatedly, and
- // we could pile up unlimited ioPrep structures. So we use a brute-force
- // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
- // Then we can free (CheckpointIO) the original one, and all live buffers
- // are still covered. (There is room for optimizations in that process.)
- //
- // The first time we prepare memory, we have the luxury that the program
- // is not running. When we do updates, the program *is* running. But maybe
- // we can use the same code both times, somehow.
-
- if (status == noErr)
- status = PrepareDCLProgramMemory(pDCLCompilerEngineData,
- dclList,
- dclListLength);
-
- // Check if there's a start event, add it and cycle count to data.
- if (status == noErr)
- {
- status = FWGetDCLProgramStartEvent(dclProgramID, &startEvent,
- &startEventState, &startEventStateMask);
-
- if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
- {
- pDCLCompilerEngineData->startEvent = startEvent;
-
- // set cycle value, ignore offset field
- pDCLCompilerEngineData->startEventState =
- (startEventState & startEventStateMask) >> kCycleOffsetPhase;
- }
- }
-
- // Allocate DMA build state record.
- pDMABuildState = (DMABuildStatePtr) PoolAllocateResident(sizeof(DMABuildState), true);
- if (pDMABuildState == nil)
- status = memFullErr;
- else
- {
- pDMABuildState->pFWIMData = pFWIMData;
- pDMABuildState->pDCLCompilerEngineData = pDCLCompilerEngineData;
- pDMABuildState->dmaPortNum = dmaPortNum;
- pDMABuildState->isochChannelNum = channelNum;
- }
-
- // Process all DCLs except label and jumps.
- pDCLCommand = dclList;
- while ((pDCLCommand != nil) && (status == noErr))
- {
- status = AddDCL(pDMABuildState, pDCLCommand, speed);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- // Process the label DCLs.
- pDCLCommand = dclList;
- while ((pDCLCommand != nil) && (status == noErr))
- {
- if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
- status = ProcessLabelDCL(pDMABuildState, (DCLLabelPtr) pDCLCommand, talking);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- // Process the jump DCLs.
- pDCLCommand = dclList;
- while ((pDCLCommand != nil) && (status == noErr))
- {
- if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLJumpOp)
- status = ProcessJumpDCL((DCLJumpPtr) pDCLCommand);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- // JKL *** do we need to do this? make sure it is handled in the DMA program
- // either InputMore with Z=0, or OutputLast* with Z=0
- //
- // if (status == noErr)
- // status = AddStopDCL (pDMABuildState);
-
- // Fill in rest of DCL engine data record.
- if (status == noErr)
- {
- pDCLCompilerEngineData->pDMAPoolDataList = pDMABuildState->pDMAPoolDataList;
- }
-
- // Save engine data.
- if (status == noErr)
- status = FWSetDCLProgramEngineData(dclProgramID, (UInt32) pDCLCompilerEngineData);
-
- // Clean up on error.
- if (status != noErr)
- {
- // Deallocate DMA pools.
- if (pDMABuildState != nil)
- if (pDMABuildState->pDMAPoolDataList != nil)
- DeallocateDMAPools(pDMABuildState->pDMAPoolDataList);
-
- // Deallocate compiler DCL data.
- if (pDCLCompilerEngineData != nil)
- if (pDCLCompilerEngineData->pDCLCompilerDCLData != nil)
- PoolDeallocate((Ptr) pDCLCompilerEngineData->pDCLCompilerDCLData);
-
- // Deallocate engine data.
- if (pDCLCompilerEngineData != nil)
- PoolDeallocate((Ptr) pDCLCompilerEngineData);
- }
-
- // Clean up.
- if (pDMABuildState != nil)
- PoolDeallocate((Ptr) pDMABuildState);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DCLCompilerModifyNotification
- //
- // Handle modification notifications for the DCL to DMA compiler.
- //zzz break this routine up
- //
-
- static OSStatus DCLCompilerModifyNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- UInt32 dclCommandNum;
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- // Get DCL command to update.
- pDCLCommand = *dclCommandList++;
-
- // Update command.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLJumpOp :
- ProcessJumpDCL((DCLJumpPtr) pDCLCommand);
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- //zzz support other transfer packet commands.
- FWDebugStr((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
- break;
-
- // Some notes from LynxFWIM ...
- // What would we do?
- // We can't do what's done below - that fills in new PCL buffer addresses. They aren't yet known.
- // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme. I notice that
- // we don't actually modify the base DCLs - I think we will have to do that. So make one pass to
- // modify the base DCLs. Then call the general-purpose memory preparation routine, and let it
- // create an all-new ioPrep (keep the old one). Once that's done, we can re-scan the list of
- // changes and make updates knowing the new physical addresses. Finally, once the updates are
- // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
- // the old ioPrep struct and free its resources. [Technically we should wait one packet to make
- // sure that whatever Lynx's current DMA engine is doing is up to date. Probably a good-enough
- // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
- // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
- //
- // We should find a safe way to make multiple updates to a PCL. The user is in trouble anyway
- // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
- // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
- // (could be bad for Lynx). Perhaps we should copy command[0], set it to NOP+last, update the
- // others, then update command[0]. That's safe unless we are inside the PCL but past command[0].
- // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
- //
- // I don't suppose the user is required to use jump-updates to deactivate part of the program
- // before updating that part? That would be 100% safe if we know the jump-update worked on time.
- //
- // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
- // structs, then we don't have to do any allocs here. (though PrepareMemForIO might anyway).
- // We know that the total number of buffers can't change, so rangeTable is OK. When we prepare
- // the physAddr table we should work out both the true size and the worst-case size. Use the
- // worst-case for alloc, use the true for PrepareMemoryForIO
- //
- // // Recast.
- // pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- //
- // // Get PCL.
- // pTransferPacketPCL =
- // LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
- //
- // // Update buffer size of transfer PCL.
- // pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
- // pclControl = (pclControl & ~kLynxDMA_TransferCount) |
- // ((pDCLTransferPacket->size) << kLynxDMA_TransferCountPhase);
- // pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
- //
- // // Update buffer address of transfer PCL.
- // // WARNING WARNING this won't work with VM on - this is a logical address
- // pTransferPacketPCL->buffer[0].address =
- // (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
-
- default :
- break;
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PrepareDCLProgramMemory
- //
- // Prepare all buffers used within a DCL program for physical I/O,
- // and determine the physical addresses. dclList is the entire program.
- //
-
- static OSStatus PrepareDCLProgramMemory(
- DCLCompilerEngineDataPtr pDCLCompilerEngineData,
- DCLCommandPtr dclList,
- UInt32 dclListLength)
- {
- DCLCommandPtr pDCL;
- DCLTransferPacketPtr pDCLTransferPacket;
- IOPreparationTable *ioPrep;
- PhysicalAddress *physAddrs; // should be PhysicalMappingTablePtr
- AddressRangeTablePtr rangeTable;
- UInt32 pageSize, pageShift;
- UInt32 pageCount, bufferCount;
- AbsoluteTime timeNow;
- OSStatus status = noErr;
-
- ioPrep = &pDCLCompilerEngineData->ioPrep;
- pageSize = pDCLCompilerEngineData->pFWIMData->pageSize;
- pageShift = pDCLCompilerEngineData->pFWIMData->pageShift;
-
- // This is gross too. Make sure we don't use stale data in lookups.
- timeNow = UpTime();
- pDCLCompilerEngineData->engineGeneration = AbsoluteToDuration(timeNow);
-
- // We will need to allocate a page table. We don't know how big it needs
- // to be, but we can wait until just before we PrepareMemoryForIO to do
- // the allocation (by then we'll know)
-
- // We need to allocate a range/length table. We fill that in before we
- // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
- // it all at once. We need one entry for each buffer in the program.
- // That's why we take a parameter indicating the program length.
- // Note if we ever allow scatter/gather buffers in a DCL program, this
- // will have to change.
-
- // We assumed (in CompileDCLProgram) that each DCL contained a buffer.
- // Some of them are branches, etc, so an optimization would be to count more
- // precisely and save a little memory.
-
- // Allocate space for rangeTable
- if (status == noErr)
- {
- rangeTable = (AddressRangeTablePtr)
- PoolAllocateResident(dclListLength * sizeof(AddressRange), false);
- if (!rangeTable)
- status = memFullErr;
-
- ioPrep->rangeInfo.multipleRanges.entryCount = 0;
- // move this below, use local copy
- ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
- }
-
- // Gather information about buffers/pointers
- if (status == noErr)
- {
- pDCL = dclList;
- bufferCount = 0; // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
- pageCount = 0; // count page table size we will need to allocate
-
- while (pDCL != nil)
- {
- switch (pDCL->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLReceivePacketStartOp :
- case kDCLReceivePacketOp :
- case kDCLSendPacketStartOp :
- case kDCLSendPacketWithHeaderStartOp :
- case kDCLSendPacketOp :
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
- rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
- rangeTable[bufferCount].length = pDCLTransferPacket->size;
- bufferCount++;
-
- // buffer + size - 1 is addr of last byte in buffer.
- // shift that right by pageShift to get page index of end.
- // subtract first page index and add one to get total page count.
-
- pageCount += // (last page - first page) + 1
- ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
- (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
- break;
-
- default : //No buffer or pointer - nothing to do
- break;
- }
-
- pDCL = pDCL->pNextDCLCommand;
- }
- }
-
- // Allocate space for page table
- if (status == noErr)
- {
- physAddrs = PoolAllocateResident(pageCount * sizeof(PhysicalAddress), false);
- if (!physAddrs)
- {
- status = memFullErr;
- PoolDeallocate((Ptr) rangeTable);
- }
- }
-
- // Prepare memory for I/O
- if (status == noErr)
- {
- ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
- kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = pageCount; // we counted exactly
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
-
- // CheckpointIO is in ReleaseIsochPort
- status = PrepareMemoryForIO(ioPrep);
- if (status != noErr)
- {
- ioPrep->mappingEntryCount = -1; // prevents CheckpointIO, kind of a hack
- PoolDeallocate((Ptr) rangeTable);
- PoolDeallocate((Ptr) physAddrs);
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AllocateDMA
- //
- // Allocate a block of DMA descriptors.
- //
-
- static OSStatus AllocateDMA(
- DMABuildStatePtr pDMABuildState,
- DMADescriptorPtr *ppDMA,
- PhysicalAddress *ppDMAPhys,
- UInt32 count)
-
- {
- DMAPoolDataPtr pDMAPoolData;
- DMADescriptorPtr pDMA,
- dmaPool;
- UInt32 dmaPoolPhys;
- UInt32 nextFreeDMA;
- UInt32 descriptorCount;
- IOPreparationTable *ioPrep;
- UInt32 pageSize;
- Ptr p;
- OSStatus status = noErr;
-
- // Get pool data record.
- pDMAPoolData = pDMABuildState->pDMAPoolDataList;
-
- // Get DMA pool and next free DMA index.
- if (pDMAPoolData != nil)
- {
- dmaPool = pDMAPoolData->DMAPoolBase;
- dmaPoolPhys = pDMAPoolData->DMAPoolBasePhys;
- nextFreeDMA = pDMAPoolData->nextFreeDMA;
- }
- else
- {
- dmaPool = nil;
- }
-
- // Allocate new pool if current pool is exhausted.
- // This pool needs to be aligned to the descriptor size for the compilation logic
- // to work properly. Pool size can exceed one phys page as long as we have an
- // allocator which gives us contiguous pages.
- //
- // JKL *** Allocate a page. Use how ever many descriptors are available in a page
- // size less the size of the DMAPoolData record.
-
-
- if ((dmaPool == nil) || ((nextFreeDMA + count) > pDMAPoolData->DMAPoolCount))
- {
- pageSize = pDMABuildState->pFWIMData->pageSize;
- p = MemAllocatePhysicallyContiguous(pageSize, true);
- if (p != nil)
- {
- // Assign DMAPoolData record to end of DMA descriptor memory
- descriptorCount = (pageSize - sizeof(DMAPoolData)) / sizeof(DMADescriptor);
- descriptorCount -= 2; // subtract two to alleviate any rounding problems and leave room for isochRxDummyQuadPhys
- pDMAPoolData = (DMAPoolDataPtr) (p + (descriptorCount * sizeof(DMADescriptor)));
- pDMAPoolData->DMAPoolCount = descriptorCount;
-
- // Prepare for IO and get physical address
- ioPrep = &pDMAPoolData->ioPrep;
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = 1; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = pDMAPoolData->physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.range.base = p;
- ioPrep->rangeInfo.range.length = pageSize;
-
- // The CheckpointIO is in DeallocateDMAPools
- status = PrepareMemoryForIO(ioPrep);
- // if (status != noErr)
- // {
- // sprintf (debugStr, "PCL Pool PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- // (long) status,
- // (long) ioPrep->rangeInfo.range.base,
- // (long) pOHCIPCLPoolData->physAddrs[0],
- // (long) ioPrep->rangeInfo.range.length);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- // }
-
- pDMAPoolData->pNextDMAPoolData = pDMABuildState->pDMAPoolDataList;
- pDMABuildState->pDMAPoolDataList = pDMAPoolData;
- pDMAPoolData->DMAPoolBase = (DMADescriptorPtr) p;
- pDMAPoolData->DMAPoolBasePhys = (UInt32) pDMAPoolData->physAddrs[0];
-
- nextFreeDMA = 0;
- dmaPool = pDMAPoolData->DMAPoolBase;
- dmaPoolPhys = pDMAPoolData->DMAPoolBasePhys;
- }
- else
- {
- status = memFullErr;
- }
- }
-
- // JKL *** Hack Alert, take a left over quad from the allocation and assign it to
- // pFWIMData->isochRxDummyQuadPhys for use in isoch receive of the first timeStamp quad.
- if ((pDMABuildState->isochRxDummyQuadPhys == 0) && (status == noErr))
- {
- pDMABuildState->isochRxDummyQuadPhys =
- dmaPoolPhys + (descriptorCount * sizeof(DMADescriptor)) + sizeof(DMAPoolData);
- }
-
- // Allocate descriptor from pool.
- if (status == noErr)
- {
- pDMA = &dmaPool[nextFreeDMA];
- nextFreeDMA += count;
- pDMAPoolData->nextFreeDMA = nextFreeDMA;
- }
-
- // Return results.
- if (status == noErr)
- {
- *ppDMA = pDMA;
- *ppDMAPhys = (PhysicalAddress) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)));
- }
- else
- {
- *ppDMA = nil;
- *ppDMAPhys = nil;
- }
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DCLCompilerNotification
- //
- // Handle update notifications for the DCL to DMA program compiler.
- //
-
- static OSStatus DCLCompilerNotification(
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- OSStatus status = noErr;
-
- switch (notificationType)
- {
- case kFWDCLUpdateNotification:
- status = DCLCompilerUpdateNotification(dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- case kFWDCLModifyNotification:
- status = DCLCompilerModifyNotification(dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- default:
- status = paramErr;
- break;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DCLCompilerUpdateNotification
- //
- // Handle update notifications for the DCL to DMA compiler. This will
- // do any neccessary CheckPointIOs and update any DCL status fields.
- //zzz do the right stuff in here
- //
-
- static OSStatus DCLCompilerUpdateNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- UInt32 dclCommandNum;
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- pDCLCommand = dclCommandList[dclCommandNum];
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- // JKL *** This is already handled in the IsochTransmitDeferredTask
- // case kDCLTimeStampOp :
- // UpdateDCLTimeStamp(pDCLCommand);
- // break;
-
- case kDCLReceivePacketStartOp :
- UpdateDCLReceivePacketStart((DCLTransferPacketPtr) pDCLCommand);
- break;
-
- // I think we might want to CheckpointIO () on the live buffers, etc...?
- default :
- break;
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // StartTalkingDCLProgram
- //
- // Start running the given DCL program.
- //
-
- static OSStatus StartTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData;
- FWIMDataPtr pFWIMData;
- OHCIRegistersPtr pOHCIRegs;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
- if (status == noErr)
- pFWIMData = pDCLCompilerEngineData->pFWIMData;
-
- // Get base address of OHCI registers.
- if (status == noErr)
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // Load physical address of DMA
- // kind of a hack, physical DMA value includes Z value
- pOHCIRegs->isochTxContext[kITContext0].commandPtr =
- EndianSwapImm32Bit((UInt32) pDCLCompilerEngineData->pStartDMA);
- SynchronizeIO ();
-
- // Setup cycle start.
- if (pDCLCompilerEngineData->startEvent == kFWDCLCycleEvent)
- {
- pOHCIRegs->isochTxContext[kITContext0].controlSet =
- EndianSwapImm32Bit(kITDMACycleMatchEnable |
- (pDCLCompilerEngineData->startEventState << kITDMACycleMatchPhase) & kITDMACycleMatch);
- SynchronizeIO();
- }
-
- // start the DMA
- pOHCIRegs->isochTxContext[kITContext0].controlSet = EndianSwapImm32Bit(kDMARun);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // StopTalkingDCLProgram
- //
- // Stop running the given DCL program.
- //
-
- static OSStatus StopTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData;
- FWIMDataPtr pFWIMData;
- OHCIRegistersPtr pOHCIRegs;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
- if (status == noErr)
- pFWIMData = pDCLCompilerEngineData->pFWIMData;
-
- // Get base address of OHCI registers.
- if (status == noErr)
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Stop the DMA.
- // zzzCould be more graceful, not send partial packet?
- pOHCIRegs->isochTxContext[kITContext0].controlClear = 0;
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ReleaseDCLProgram
- //
- // Release the resources allocated for the given DCL program.
- //
-
- static OSStatus ReleaseDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData;
- FWIMDataPtr pFWIMData;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
- if (status == noErr)
- pFWIMData = pDCLCompilerEngineData->pFWIMData;
-
- if (status == noErr)
- {
- // Deallocate DMA pools.
- if (pDCLCompilerEngineData->pDMAPoolDataList != nil)
- {
- DeallocateDMAPools(pDCLCompilerEngineData->pDMAPoolDataList);
- }
-
- // Release all VM resources
- // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
- if (pDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
- {
- status = CheckpointIO (pDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
- // if (status != noErr)
- // {
- // sprintf (debugStr, "DCL data CheckpointIO status %ld",
- // (long) status);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- // }
- PoolDeallocate ((Ptr) pDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
- PoolDeallocate ((Ptr) pDCLCompilerEngineData->ioPrep.physicalMapping);
- }
-
- // Deallocate compiler data list for DCLs
- if (pDCLCompilerEngineData->pDCLCompilerDCLData != nil)
- PoolDeallocate ((Ptr) pDCLCompilerEngineData->pDCLCompilerDCLData);
-
- // Deallocate engine data.
- PoolDeallocate ((Ptr) pDCLCompilerEngineData);
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ReleaseIsochPort
- //
- // Release resources allocated for the given isochronous channel.
- //
-
- static OSStatus ReleaseIsochPort(
- FWIMDataPtr pFWIMData,
- IsochPortDataPtr pIsochPortData)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData = nil;
- OSStatus status = noErr;
-
- // Release DCL resources.
- if (pIsochPortData->originalDCLProgramID != (DCLProgramID) kInvalidDCLProgramID)
- status = FWReleaseDCLProgram(pIsochPortData->originalDCLProgramID);
-
- // Deallocate isoch port data record.
- PoolDeallocate((Ptr) pIsochPortData);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // StartListeningDCLProgram
- //
- // Start running the given DCL program.
- //
-
- static OSStatus StartListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData;
- FWIMDataPtr pFWIMData;
- OHCIRegistersPtr pOHCIRegs;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
- if (status == noErr)
- pFWIMData = pDCLCompilerEngineData->pFWIMData;
-
- // Get base address of OHCI registers.
- if (status == noErr)
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // Load physical address of starting DMA,
- // Kind of a hack, already added Z value to pStartDMA physical address
- pOHCIRegs->isochRxContext[kIRContext0].commandPtr =
- EndianSwapImm32Bit((UInt32) pDCLCompilerEngineData->pStartDMA);
- SynchronizeIO ();
-
- // Setup cycle start.
- if (pDCLCompilerEngineData->startEvent == kFWDCLCycleEvent)
- {
- pOHCIRegs->isochRxContext[kIRContext0].controlSet = EndianSwapImm32Bit(kIRDMACycleMatchEnable);
- pOHCIRegs->isochRxContext[kIRContext0].match =
- EndianSwapImm32Bit((pDCLCompilerEngineData->startEventState << kIRDMACycleMatchPhase) & kIRDMACycleMatch);
- SynchronizeIO();
- }
-
- // start the DMA
- pOHCIRegs->isochRxContext[kIRContext0].controlSet = EndianSwapImm32Bit(kDMARun);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // StopListeningDCLProgram
- //
- // Stop running the given DCL program.
- //
-
- static OSStatus StopListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCompilerEngineDataPtr pDCLCompilerEngineData;
- FWIMDataPtr pFWIMData;
- OHCIRegistersPtr pOHCIRegs;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
- if (status == noErr)
- pFWIMData = pDCLCompilerEngineData->pFWIMData;
-
- // Get base address of OHCI registers.
- if (status == noErr)
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Stop the DMA - zzz could be more graceful, not stop mid-packet.
- //zzz need way to bit bucket any remaining packets in FIFO
- pOHCIRegs->isochRxContext[kIRContext0].controlClear = EndianSwapImm32Bit(kDMARun);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddDCL
- //
- // Add the packet DCL command to the DMA program.
- //
- // The DMA program is built in two passes, the first creates all of the
- // packet DMA descriptors, handles DCL's that generate interrupts such
- // as TimeStamp, CallProc, and Update, and sets up some of the jump/label
- // information. The second pass completes the labels and jumps.
- //
- // JKL *** There may be some problems handling updates and dynamic values with this.
- //
-
- static OSStatus AddDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed)
- {
- UInt32 opcode;
- OSStatus status = noErr;
-
- // Dispatch off of opcode.
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
- switch (opcode)
- {
- case kDCLReceivePacketStartOp:
- status = AddReceivePacketStartDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLReceivePacketOp:
- status = AddReceivePacketDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketStartOp:
- status = AddSendPacketStartDCL(pDMABuildState, pDCLCommand, speed);
- break;
-
- case kDCLSendPacketWithHeaderStartOp:
- status = AddSendPacketWithHeaderStartDCL(pDMABuildState, pDCLCommand, speed);
- break;
-
- case kDCLSendPacketOp:
- status = AddSendPacketDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLCallProcOp:
- status = AddCallProcDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLSetTagSyncBitsOp:
- status = AddSetTagSyncBitsDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLUpdateDCLListOp:
- status = AddUpdateDCLListDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLTimeStampOp:
- status = AddTimeStampDCL(pDMABuildState, pDCLCommand);
- break;
-
- case kDCLJumpOp:
- status = AddJumpAddress(pDMABuildState, pDCLCommand);
- break;
-
- default:
- break;
- }
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DeallocateDMAPools
- //
- // Deallocate the given list of DMA descriptor pools.
- //
-
- static void DeallocateDMAPools(
- DMAPoolDataPtr pDMAPoolDataList)
- {
- DMAPoolDataPtr pDMAPoolData,
- pNextDMAPoolData;
- OSStatus status = noErr;
-
- // Deallocate each pool in list.
- pDMAPoolData = pDMAPoolDataList;
- while (pDMAPoolData != nil)
- {
- pNextDMAPoolData = pDMAPoolData->pNextDMAPoolData;
- status = CheckpointIO(pDMAPoolData->ioPrep.preparationID, kNilOptions);
- // if (status != noErr)
- // {
- // sprintf (debugStr, "PCL Pool CheckpointIO status %ld ID was %08lx",
- // (long) status,
- // (long) pNextOHCIPCLPoolData->ioPrep.preparationID);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- // }
-
- status = MemDeallocatePhysicallyContiguous(pDMAPoolData->DMAPoolBase);
- // if (status != noErr)
- // FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
-
- pDMAPoolData = pNextDMAPoolData;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddReceivePacketStartDCL
- //
- // Add a receive packet start DCL.
- //
-
- static OSStatus AddReceivePacketStartDCL (
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- FWIMDataPtr pFWIMData;
- DCLTransferPacketPtr pDCLTransferPacket;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCompilerDCLDataPtr pInterruptDCLCompilerDCLData;
- DMADescriptorPtr pDoDMA, pDMA;
- PhysicalAddress pDMAPhys;
- PhysicalAddress physTable[7]; // 7 is max, we use one for dummy header quad
- UInt32 sizeTable[7];
- UInt32 packetSize, packetPageCount;
- UInt32 pageCount, pageIndex, pageSize;
- UInt32 startingInterruptCount;
- OSStatus status = noErr;
- Boolean needsInterrupt = false;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
- pFWIMData = pDMABuildState->pFWIMData;
-
- // Scan for any ReceivePacketOp DCLs that follow this ReceivePacketStartOp DCL.
- // They will all combine with this one to send a single packet. Find out
- // all of the physical addresses and data sizes, including descriptor count.
-
- packetSize = 0;
- packetPageCount = 0;
- pageSize = pFWIMData->pageSize;
-
- // Get physical addresses.
- do
- {
- packetSize += pDCLTransferPacket->size;
- pageCount = DataMapToPhysical(pDMABuildState->pDCLCompilerEngineData,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- &physTable[packetPageCount]);
-
- // determine reqCount for preliminary page(s)
- for (pageIndex = 0; pageIndex < (pageCount - 1); pageIndex++, packetPageCount++)
- {
- if (pageIndex == 0)
- sizeTable[packetPageCount] = pageSize - ((UInt32) pDCLTransferPacket->buffer & (pageSize - 1));
- else
- sizeTable[packetPageCount] = pageSize;
- }
-
- // determine reqCount for last page, could also be first page
- if (pageCount == 1)
- sizeTable[packetPageCount] = pDCLTransferPacket->size;
- else
- sizeTable[packetPageCount] = ((UInt32) pDCLTransferPacket->buffer + pDCLTransferPacket->size) & (pageSize - 1);
-
- packetPageCount++;
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
-
- if (pDCLTransferPacket != nil)
- {
- if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
- {
- // look ahead to see if packet receipt needs to trigger interrupt
- // save interrupt count since it gets updated in this routine
- startingInterruptCount = pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum];
- needsInterrupt = AddReceiveDCLInterrupt((DCLCommandPtr) pDCLTransferPacket, pFWIMData, pDMABuildState->dmaPortNum);
-
- pDCLTransferPacket = nil;
- }
- }
-
- } while (pDCLTransferPacket != nil);
-
- if (packetPageCount > 7)
- {
- status = -1;
- FWDebugStr("\pAddSendPacketStartDCL, too many descriptors");
- }
-
- packetPageCount++;
- packetSize += 4;
-
- // Allocate contiguous descriptors
- if (status == noErr)
- {
- status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, packetPageCount);
- pDoDMA = pDMA;
- }
-
- // fill in descriptor for first dummy quad
- if (status == noErr)
- {
- // Set up INPUT_MORE descriptor.
- // JKL *** What about wait control for sync field
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(kInputMoreCmd << kDMACommandPhase | 4);
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit(pDMABuildState->isochRxDummyQuadPhys);
- pDoDMA->descriptorField[2] = 0;
- pDoDMA->descriptorField[3] = EndianSwapImm32Bit(4);
- pDoDMA++;
- }
-
- // fill in DMA descriptor block
- if (status == noErr)
- {
- // For buffers that take up more than a page, set up INPUT_MORE
- // descriptors for the prelimary pages
- for (pageIndex = 0; pageIndex < (packetPageCount - 2); pageIndex++)
- {
- // Set up INPUT_MORE descriptor.
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(kInputMoreCmd << kDMACommandPhase | sizeTable[pageIndex]);
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
- pDoDMA->descriptorField[2] = 0;
- pDoDMA->descriptorField[3] = EndianSwapImm32Bit(sizeTable[pageIndex]);
- pDoDMA++;
- }
-
- // Set up INPUT_LAST descriptor.
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
- kInputLastCmd << kDMACommandPhase | // packet-per-buffer mode
- kBranchAlways << kDMABranchPhase | // branch to next descriptor
- sizeTable[pageIndex]); // rest of packet buffer
- if (needsInterrupt)
- {
- // set interrupt and update status bits
- pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
-
- // save xfer status descriptor field address in DCLInterrupt record
- // when interrupt comes in, check xfer status to see if descriptor completed, yuck
- while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
- {
- pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
- [startingInterruptCount].pDCLCommand;
- pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
- startingInterruptCount++;
- }
- }
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
- pDoDMA->descriptorField[3] = EndianSwapImm32Bit(sizeTable[pageIndex]); // set resCount to descriptor buffer size
- }
-
- // Link previous descriptor and add Z value.
- if ((status == noErr) && pDMABuildState->pLastBranch)
- *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + packetPageCount);
-
- if (status == noErr)
- // The next descriptor's address goes here
- pDMABuildState->pLastBranch = (UInt32 *) &pDoDMA->descriptorField[2];
-
- // Initialize start DMA if not already set. Add Z value to address.
- if ((status == noErr) && (pDMABuildState->pDCLCompilerEngineData->pStartDMA == nil))
- {
- pDMABuildState->pDCLCompilerEngineData->pStartDMA = (UInt32) pDMAPhys + packetPageCount;
- }
-
- // Store results in DCL transfer packet record.
- //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
- // but I don't think it ever gets used, unless we update buffers (NYI anyway)
- // Also store Z value in DMAPhys for use by label/jump. Mask 4 Z value bits
- // if address is ever used.
- if (status == noErr)
- {
- pDCLCompilerDCLData->pDMA = pDMA;
- pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + packetPageCount);
- }
- else
- {
- pDCLCompilerDCLData->pDMA = nil;
- pDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddReceiveDCLInterrupt
- //
- // Look ahead at DCL commands to see if any interrupt opcodes follow a receive
- // DCL. Add them to the interrupt list. The receive DCL processor will then
- // add additional information to the new interrupt records.
- //
- static Boolean AddReceiveDCLInterrupt (
- DCLCommandPtr pDCLCommand,
- FWIMDataPtr pFWIMData,
- UInt32 portNum)
- {
- UInt32 opcode;
- DCLProgramInterruptPtr pDCLInterrupt;
- Boolean foundInterruptDCL = false;
-
- while (pDCLCommand != nil)
- {
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
-
- switch (opcode)
- {
- case kDCLCallProcOp:
- case kDCLUpdateDCLListOp:
- case kDCLTimeStampOp:
- if (pFWIMData->numDCLInterrupts[portNum] < kNumDCLInterrupts)
- {
- foundInterruptDCL = true;
- pDCLInterrupt = &pFWIMData->pDCLInterruptList[portNum][pFWIMData->numDCLInterrupts[portNum]];
- pDCLInterrupt->pDCLCommand = pDCLCommand;
- pDCLInterrupt->pendingInterrupt = false;
- pFWIMData->numDCLInterrupts[portNum]++;
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
- else
- {
- pDCLCommand = nil;
- FWDebugStr("\pAddReceiveDCLInterrupt, need more DCLProgramInterrupt records");
- }
-
- break;
-
- case kDCLLabelOp:
- case kDCLJumpOp:
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- break;
-
- default:
- pDCLCommand = nil;
- }
- }
-
- return foundInterruptDCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DataMapToPhysical
- //
- // Look up physical addresses for buffers/pointers.
- // Fills in the passed page table, returns page count (0 if not found)
- //
- static UInt32 DataMapToPhysical (
- DCLCompilerEngineDataPtr pDCLCompilerEngineData,
- Ptr pBuffer,
- UInt32 size,
- PhysicalMappingTablePtr returnTable)
- {
- UInt32 pageCount = 0, lookCount = 0;
- UInt32 pageShift;
- static UInt32 rangeLook = 0, pageLook = 0;
- static UInt32 cacheEngineGeneration = 0;
- IOPreparationTable *ioPrep = &pDCLCompilerEngineData->ioPrep;
- AddressRangeTablePtr try;
-
- pageShift = pDCLCompilerEngineData->pFWIMData->pageShift;
-
- // Look up phys addrs in our prepared table
- // Return in provided page table
-
- // Start lookup from last known point, if we build in order, lookup is fast
- // Strictly speaking, rangeLook and pageLook should be static to the
- // engine data, not the whole FWIM, but I don't think we can compile more
- // than one DCL program at a time anyway.
- //
- // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
- // because they may be off the end or otherwise inaccurate.
- //
- // I'm not sure this (optimization) works - it still seems sluggish.
-
- if (cacheEngineGeneration != pDCLCompilerEngineData->engineGeneration)
- {
- cacheEngineGeneration = pDCLCompilerEngineData->engineGeneration;
- rangeLook = 0;
- pageLook = 0;
- }
-
- // Repeat until we find it or run out of places to look
-
- while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && !pageCount)
- {
- try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
-
- // pageCount is number of physAddr entries used by this range
- // either copy them (found) or skip over them (not found)
-
- pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
- ((UInt32) try->base >> pageShift);
-
- // require exact match
- if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
- {
- // Found pages we want. Copy page table.
- BlockMoveData(&ioPrep->physicalMapping[pageLook],
- returnTable,
- pageCount * sizeof (PhysicalAddress));
- pageLook += pageCount;
- }
- else
- {
- // These aren't the pages we're looking for. Skip forward.
- pageLook += pageCount;
- pageCount = 0;
- }
-
- lookCount++;
- rangeLook++;
- if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
- {
- rangeLook = 0;
- pageLook = 0;
- }
- }
-
- // if (!pageCount)
- // FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
-
- return pageCount;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddReceivePacketDCL
- //
- // Add a receive packet DCL. Don't need to do anything. Any ReceivePacketDCL's
- // already got processed by the preceding AddReceivePacketStartDCL routine.
- //
- //
-
- static OSStatus AddReceivePacketDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddTimeStampDCL
- //
- // Add a time stamp DCL.
- //
- // This DCL should already be handled by the send packet DCL processing routine.
- //
- // The DCL gets saved in a list of interrupt driven DCL's and the xfer
- // status address of the DMA descriptor corresponding to the previous
- // DCL also gets saved in the interrupt list. Upon interrupt the interrupt
- // list gets scanned and checks the transfer status. If it is non-zero then
- // the descriptor block has been completed and a needsInterruptProcessing
- // bit is set along with posting a deferred task for later interrupt processing.
- //
- // During the deferred task processing, the interrupt DCL's are scanned to
- // check if they need processing. If they do, then they are processed, the
- // xferStatus field is cleared, and then the needsInterruptProcessing flag
- // is cleared.
- //
- // For this DCL the time stamp when the packet was sent is in the xferStatus
- // field. Copy it into the DCL record at interrupt processing time.
- //
-
- static OSStatus AddTimeStampDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- // This should already be handled in the send packet start DCL routine.
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddSendPacketStartDCL
- //
- // Add a send packet start DCL.
- //
-
- static OSStatus AddSendPacketStartDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed)
- {
- FWIMDataPtr pFWIMData;
- DCLTransferPacketPtr pDCLTransferPacket;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCompilerDCLDataPtr pInterruptDCLCompilerDCLData;
- UInt32 packetSize, packetPageCount;
- PhysicalAddress physTable[7]; // 7 is max
- UInt32 sizeTable[7];
- UInt32 pageSize, pageCount, pageIndex;
- UInt32 branchAddress;
- DMADescriptorPtr pDMA, pDoDMA;
- PhysicalAddress pDMAPhys;
- UInt32 startingInterruptCount;
- OSStatus status = noErr;
- Boolean needsInterrupt = false;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
- pFWIMData = pDMABuildState->pFWIMData;
-
- // Scan any SendPacketOp DCLs that follow this SendPacketStartOp DCL.
- // They will all combine with this one to send a single packet. Find out
- // all of the physical addresses and data sizes, including descriptor count.
- //
- // JKL *** What about zero size packets, this should all still work if
- // DataMapToPhysical returns a pageCount of 1 for a zero size packet.
- // If not only one descriptor would get allocate and two are needed.
- // The zero size packet case could get handled by a separate routine.
-
- packetSize = 0;
- packetPageCount = 0;
- pageSize = pFWIMData->pageSize;
-
- do
- {
- packetSize += pDCLTransferPacket->size;
- pageCount = DataMapToPhysical(pDMABuildState->pDCLCompilerEngineData,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- &physTable[packetPageCount]);
-
- for (pageIndex = 0; pageIndex < (pageCount - 1); pageIndex++, packetPageCount++)
- {
- // determine reqCount for preliminary page(s)
- if (pageIndex == 0)
- sizeTable[packetPageCount] = pageSize - ((UInt32) pDCLTransferPacket->buffer & (pageSize - 1));
- else
- sizeTable[packetPageCount] = pageSize;
- }
-
- // determine reqCount for last page
- if (pageCount == 1)
- sizeTable[packetPageCount] = pDCLTransferPacket->size;
- else
- sizeTable[packetPageCount] = ((UInt32) pDCLTransferPacket->buffer + pDCLTransferPacket->size) & (pageSize - 1);
-
- packetPageCount++;
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
-
- if (pDCLTransferPacket != nil)
- {
- if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
- {
- // look ahead to see if packet receipt needs to trigger interrupt
- // save interrupt count since it gets updated in this routine
- startingInterruptCount = pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum];
- needsInterrupt = AddTransmitDCLInterrupt((DCLCommandPtr) pDCLTransferPacket, pFWIMData, pDMABuildState->dmaPortNum);
-
- pDCLTransferPacket = nil;
- }
- }
-
- } while (pDCLTransferPacket != nil);
-
- if (packetPageCount > 6)
- {
- status = -1;
- FWDebugStr("\pAddSendPacketStartDCL, too many descriptors");
- }
-
- if (status == noErr)
- {
- // Allocate new descriptor. Special case null packets.
- if (packetSize == 0)
- packetPageCount++;
- else
- packetPageCount += 2;
-
- status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, packetPageCount);
-
- pDoDMA = pDMA;
- }
-
- // fill out start descriptor
- if (status == noErr)
- {
- if (packetSize == 0)
- { // handle zero length packet
- // use output last immediate (uses 2 dma descriptors)
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit( 8 | // reqCount = 8 for immediate
- kOutputLastImmCmd << kDMACommandPhase |
- kOutputLastImmKey << kDMAKeyPhase |
- kOutputLastBranch << kDMABranchPhase);
- if (needsInterrupt)
- {
- // set interrupt and update status bits
- pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
-
- // save last DMA descriptor in interrupt DCL's data
- // when interrupt comes in, check xfer status to see if descriptor completed, yuck
- while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
- {
- pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
- [startingInterruptCount].pDCLCommand;
- pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
- startingInterruptCount++;
- }
- }
- pDoDMA->descriptorField[2] = 0; // branch address for later use
- pDoDMA->descriptorField[3] = 0; // status for later use
-
- // The next descriptor's address for branching goes here.
- branchAddress = (UInt32) &pDoDMA->descriptorField[2];
-
- // put header quads in second part of descriptor
- // JKl *** set speed, tag, synch bits
- pDoDMA++;
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
- pDMABuildState->syncBits |
- kFWTCodeIsochronousBlock << kIsochTCodePhase |
- pDMABuildState->isochChannelNum << kIsochTxChannelPhase |
- pDMABuildState->tagBits << kIsochTagPhase |
- speed << kIsochTxSpeedPhase);
- pDoDMA->descriptorField[1] = 0;
- }
- else
- {
- // use output more immediate (uses 2 dma descriptors)
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(8 | // reqCount 8 for immediate
- kOutputMoreImmCmd << kDMACommandPhase |
- kOutputMoreImmKey << kDMAKeyPhase);
-
- // Set skip address to resend same packet
- pDoDMA->descriptorField[2] = (UInt32) pDMAPhys + packetPageCount;
-
- // put header quads in second part of descriptor
- // JKl *** set speed, tag, synch bits
- pDoDMA++;
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
- pDMABuildState->syncBits |
- kFWTCodeIsochronousBlock << kIsochTCodePhase |
- pDMABuildState->isochChannelNum << kIsochTxChannelPhase |
- pDMABuildState->tagBits << kIsochTagPhase |
- speed << kIsochTxSpeedPhase);
- // set packetSize
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit(packetSize << kIsochTxDataLengthPhase);
-
- pDoDMA++;
- }
- }
-
- if ((status == noErr) && (packetSize > 0))
- {
- // fill in pereliminary OUTPUT_MORE descriptors, subtracting three from packetPageCount:
- // first two descriptors are for output_immediate and last one is for output_last
- for (pageIndex = 0; pageIndex < (packetPageCount - 3); pageIndex++)
- {
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit(sizeTable[pageIndex]); // reqCount, rest 0
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
-
- pDoDMA++;
- }
-
- // complete packet with OUTPUT_LAST descriptor
- pDoDMA->descriptorField[0] = EndianSwapImm32Bit (
- sizeTable[pageIndex] | // reqCount
- kOutputLastBranch << kDMABranchPhase |
- kOutputLastCmd << kDMACommandPhase);
- if (needsInterrupt)
- {
- // set interrupt and update status bits
- pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
-
- // save DMA descriptor address in DCLInterrupt record
- // when interrupt comes in, check xfer status to see if descriptor completed, yuck
- while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
- {
- pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
- [startingInterruptCount].pDCLCommand;
- pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
- startingInterruptCount++;
- }
- }
- pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
- pDoDMA->descriptorField[2] = 0; // used later for branch address
- pDoDMA->descriptorField[3] = 0; // used later for transfer status
-
- // The next descriptor's address for branching goes here.
- branchAddress = (UInt32) &pDoDMA->descriptorField[2];
- }
-
- // Link previous descriptor and add Z value
- if (status == noErr)
- {
- if (pDMABuildState->pLastBranch)
- *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + packetPageCount);
- }
-
- // Store the address for the next descriptor's start
- if (status == noErr)
- pDMABuildState->pLastBranch = (UInt32 *) branchAddress;
-
- // Initialize start DMA if not already set. Add Z value to address.
- if ((status == noErr) && (pDMABuildState->pDCLCompilerEngineData->pStartDMA == nil))
- pDMABuildState->pDCLCompilerEngineData->pStartDMA = (UInt32) pDMAPhys + packetPageCount;
-
- // Store results in DCL transfer packet record.
- //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
- // but I don't think it ever gets used, unless we update buffers (NYI anyway)
- // Add Z value to DMAPhys for label/jump use. Mask 4 Z value bits if physical
- // address if needed.
- if (status == noErr)
- {
- pDCLCompilerDCLData->pDMA = pDMA;
- pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + packetPageCount);
- }
- else
- {
- pDCLCompilerDCLData->pDMA = nil;
- pDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddSendPacketWithHeaderStartDCL
- //
- // Adds a send packet with header start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus AddSendPacketWithHeaderStartDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand,
- UInt32 speed)
- {
- // JKL *** Similar SendPacketStart with the addition of adding the header
- // to the descriptor and possibly changing transmit context settings.
-
- FWDebugStr ("\pAddSendPacketWithHeaderStartDCL, not yet implemented");
- return -1;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddTransmitDCLInterrupt
- //
- // Look ahead at DCL commands to see if any interrupt opcodes follow a transmit
- // DCL. Add them to the interrupt list. The transmit DCL processor will then
- // add additional information to the new interrupt records.
- //
- static Boolean AddTransmitDCLInterrupt (
- DCLCommandPtr pDCLCommand,
- FWIMDataPtr pFWIMData,
- UInt32 portNum)
- {
- UInt32 opcode;
- DCLProgramInterruptPtr pDCLInterrupt;
- Boolean foundInterruptDCL = false;
-
- while (pDCLCommand != nil)
- {
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
-
- switch (opcode)
- {
- case kDCLCallProcOp:
- case kDCLUpdateDCLListOp:
- case kDCLTimeStampOp:
- if (pFWIMData->numDCLInterrupts[portNum] < kNumDCLInterrupts)
- {
- foundInterruptDCL = true;
- pDCLInterrupt = &pFWIMData->pDCLInterruptList[portNum][pFWIMData->numDCLInterrupts[portNum]];
- pDCLInterrupt->pDCLCommand = pDCLCommand;
- pDCLInterrupt->pendingInterrupt = false;
- pFWIMData->numDCLInterrupts[portNum]++;
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
- else
- {
- pDCLCommand = nil;
- FWDebugStr("\pAddTransmitDCLInterrupt, need more DCLProgramInterrupt records");
- }
-
- break;
-
- case kDCLLabelOp: // skip over any label or jumps continuing looking for interrupt Ops
- case kDCLJumpOp:
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- break;
-
- default:
- pDCLCommand = nil;
- }
- }
- return foundInterruptDCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddSendPacketDCL
- //
- // Add a send packet DCL.
- //
- // There's nothing to do here, since the portion of the packet described by
- // this DCL is already processed in the preceeding SendPacketStartOp.
-
- static OSStatus AddSendPacketDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddCallProcDCL
- //
- // Add a call proc DCL.
- //
- // This DCL should already be handled by the packet DCL processing routines.
- //
- // The DCL gets saved in a list of interrupt driven DCL's. The xferStatus
- // address of the DMA descriptor corresponding to the previous DCL
- // also gets saved in the interrupt list. Upon interrupt the interrupt
- // list gets scanned and checks the transfer status. If it is non-zero then
- // the descriptor block has been completed and a needsInterruptProcessing
- // bit is set along with posting a deferred task for later interrupt processing.
- //
- // During the deferred task processing, the interrupt DCL's are scanned to
- // check if they need processing. If they do, then they are processed, the
- // xferStatus field is cleared, and then the needsInterruptProcessing flag
- // is cleared.
- //
- // For this DCL the callProc will be called through FireWire services.
- //
- // This would not work if someone wanted to place a CallProc at the beginning of
- // the DCL, would anyone want to do that? JKL ****
- //
-
- static OSStatus AddCallProcDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- // This should already be handled in the packet start DCL routines.
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // UpdateDCLListDCL
- //
- // Add a update DCL list DCL. Same description as routine above.
- //
-
- static OSStatus AddUpdateDCLListDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- // This should already be handled in the packet start DCL routines.
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddJumpAddress
- //
- // Add the preceding DMA's branch address field to the jump DCL data.
- //
-
- static OSStatus AddJumpAddress(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLJumpPtr pDCLJump;
- OSStatus status = noErr;
-
- // recast DCL command
- pDCLJump = (DCLJumpPtr) pDCLCommand;
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLJump->compilerData;
-
- // store the address for the branch field in the dmaPhys field
- pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) pDMABuildState->pLastBranch;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ProcessJumpDCL
- //
- // Process a jump DCL.
- //
- // The jump DCL has the address of the branch field filled in during packet
- // DCL processing. Update the branch field with the address stashed
- // in the corresponding label field. That address has Z value stored in it.
- //
-
- static OSStatus ProcessJumpDCL(
- DCLJumpPtr pDCLJump)
- {
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCompilerDCLDataPtr pLabelDCLCompilerDCLData;
- DCLLabelPtr pDCLLabel;
- OSStatus status = noErr;
-
- // get DCL command compiler data
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLJump->compilerData;
-
- // get label record
- pDCLLabel = (DCLLabelPtr) pDCLJump->pJumpDCLLabel;
- pLabelDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- if (pDCLCompilerDCLData->pDMAPhys != nil)
- *((UInt32 *) pDCLCompilerDCLData->pDMAPhys) = EndianSwapImm32Bit((UInt32) pLabelDCLCompilerDCLData->pDMAPhys);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ProcessLabelDCL
- //
- // Add a label DCL.
- //
- // Look ahead to the next packet DCL and store its physical DMA address for
- // a jump instruction to use as a branch.
- //
- // JKL *** Some label DCL ops may come at the end of a DCL program with no Send/
- // Receive PacketStarts following it. In that case what to do, since the process
- // has been to key the label off of the next Send/Receive PacketStart?
- //
- // For isoch transmit create an output_last descriptor indicating no packet is to
- // be sent for the current cycle. Attach the label to that descriptor. Normally there
- // is also interrupt requests following this label, such as update or callProc. They
- // get keyed off the previous Send/Receive PacketStart not this new dummy descriptor.
- // The DCL program might want to jump to that label from somewhere else and execute
- // the interrupt driven ops. This won't happen in this case since the interrupt is
- // not keyed off this dummy descriptor.
- //
- // For isoch receive when there is a label at the end of a program, attach this label
- // back to the first ReceivePacketStart DCL in the program. Again you can run into
- // the same problem described above where the intention may be to execute some update
- // or callProc after the label, but that does not happen since the interrupt needed to
- // make that execution happen is keyed off of the previous ReceivePacket op.
- //
-
- static OSStatus ProcessLabelDCL(
- DMABuildStatePtr pDMABuildState,
- DCLLabelPtr pDCLLabel,
- Boolean talking)
- {
- DCLCommandPtr pDCLCommand;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData,
- pNextDCLCompilerDCLData;
- DMADescriptorPtr pDMA;
- PhysicalAddress pDMAPhys;
- UInt32 opcode;
- OSStatus status = noErr;
-
- // get DCL command compiler data
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- // look at next DCL
- pDCLCommand = pDCLLabel->pNextDCLCommand;
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
-
- // skip over any DCL's until the next Send or Receive packet startOp is found
- while ((pDCLCommand != nil) && (opcode != kDCLSendPacketStartOp) && (opcode != kDCLReceivePacketStartOp))
- {
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
- }
-
- // JKL *** this only works for isoch transmit and creates a descriptor to indicate
- // no packet shold be sent for the current cycle. I think this is OK since if you ever
- // get to this descriptor, things may be in bad shape.
- if ((pDCLCommand == nil) && talking)
- {
- // create a single output_last descriptor so the jump has an address/label to jump to
- status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, 1);
- if (status == noErr)
- {
- pDMA->descriptorField[0] = EndianSwapImm32Bit(0 |
- kOutputLastCmd << kDMACommandPhase |
- kOutputLastKey << kDMAKeyPhase |
- kOutputLastBranch << kDMABranchPhase);
- pDMA->descriptorField[2] = 0;
- pDMA->descriptorField[3] = 0;
-
- // update branch address and value
- if (pDMABuildState->pLastBranch)
- *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + 1);
-
- pDMABuildState->pLastBranch = (UInt32 *) &pDMA->descriptorField[2];
- }
- }
-
- if (pDCLCommand != nil)
- {
- pNextDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
-
- // JKL *** Could DMAPhys be nil?
- pDCLCompilerDCLData->pDMAPhys = pNextDCLCompilerDCLData->pDMAPhys;
- }
- else
- {
- if (talking)
- // point label to new dummy descriptor
- pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + 1);
- else
- // label is at end of DMA program, loop back to start
- pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) pDMABuildState->pDCLCompilerEngineData->pStartDMA;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // AddSetTagSyncBitsDCL
- //
- // Add a set tag and sync bits DCL. Store the values in DMA build record for
- // all future descriptor processing.
- //
- // JKL *** Will those include following execution (jumps) properly.
- //
-
- static OSStatus AddSetTagSyncBitsDCL(
- DMABuildStatePtr pDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLSetTagSyncBitsPtr pDCLSetTagSyncBits;
- OSStatus status = noErr;
-
- // Recast DCL command, get data.
- pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
-
- // set values in DMABuild record
- pDMABuildState->tagBits = pDCLSetTagSyncBits->tagBits;
- pDMABuildState->syncBits = pDCLSetTagSyncBits->syncBits;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // UpdateDCLTimeStamp
- //
- // Update a DCL time stamp. It reads the time stamp out of a DMA descriptor
- // and writes it into the timeStamp field of the DCL.
- //
-
- static OSStatus UpdateDCLTimeStamp(
- DCLTimeStampPtr pDCLTimeStamp)
- {
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- UInt32 timeStamp;
- OSStatus status = noErr;
-
- // Get DCL compiler data.
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTimeStamp->compilerData;
-
- // Copy time stamp from saved status/timeStamp descriptor field.
- // Xfer status has 3 second bits and 12 cycle count bits, shift to match cycle count register.
- // JKL *** should the rest of the seconds bits be or'd in from the cycle count, checking for
- // an overflow that would need to increment the first three seconds bits. Otherwise hopefully
- // the high four bits of seconds would not have changed by the time this is executed.
- timeStamp = EndianSwapImm32Bit(pDCLCompilerDCLData->pDMA->descriptorField[3]) & kDMATimeStamp;
- pDCLTimeStamp->timeStamp = timeStamp << 12;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // UpdateDCLReceivePacketStart
- //
- // Update DCL receive packet start. Byte swap the packet header.
- //
-
- static OSStatus UpdateDCLReceivePacketStart(
- DCLTransferPacketPtr pDCLTransferPacket)
- {
- UInt32 packetHeader;
- OSStatus status = noErr;
-
- // Byte swap the header
- packetHeader = *((UInt32 *) pDCLTransferPacket->buffer);
- *((UInt32 *) pDCLTransferPacket->buffer) = EndianSwapImm32Bit(packetHeader);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // HandleIsochRxInterrupt
- //
- // Handle isoch receive interrupts.
- //
- // Scan the DCL interrupt list and update needsInterrupt field for each.
- // Schedule deferred task.
- //
- // JKL *** Is this too much processing for interruptPending time? Time it.
- // *** portNum needs to be available for multiple contexts,
- // maybe use context numbers somehow
- //
-
- void HandleIsochRxInterrupt(
- FWIMDataPtr pFWIMData)
- {
- DCLCommandPtr pDCLCommand;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- OHCIRegistersPtr pOHCIRegs;
- UInt32 interruptStatus, interruptStatusLittleEndian;
- UInt32 interruptDCLIndex;
- UInt32 portNum;
- OSStatus status = noErr;
-
- // Get our register base address.
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Read separate isoch receive interrupt status register to determine context that
- // interrupt is for. intEventClear reads the masked version of interrupt status
- // intEventSet reads the interrupt status without mask. Not used.
- interruptStatusLittleEndian = pOHCIRegs->isochRxIntEventClear;
- interruptStatus = EndianSwapImm32Bit(interruptStatusLittleEndian);
-
- portNum = kIsochReceivePort;
-
- // scan DCL interrupt list looking for DCL's that have completed
- for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
- {
- pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- if (EndianSwapImm32Bit(pDCLCompilerDCLData->pDMA->descriptorField[3]) & kDMATransferStatus)
- pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = true;
- }
-
- if (!pFWIMData->isochReceiveDTScheduled)
- {
- status = FWScheduleDeferredTask(pFWIMData->isochReceiveDeferredTaskID, nil);
-
- if (status == noErr)
- pFWIMData->isochReceiveDTScheduled = true;
- }
-
- pOHCIRegs->isochRxIntEventClear = interruptStatusLittleEndian;
- SynchronizeIO();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // HandleIsochTxInterrupt
- //
- // Handle isoch transmit interrupts.
- //
- // Scan the DCL interrupt list and update interruptPending field for each.
- // Schedule deferred task.
- //
- // JKL *** Is this too much processing for interrupt time? Time it.
- // *** portNum needs to be available for multiple contexts,
- // maybe use context numbers somehow
- //
-
- void HandleIsochTxInterrupt(
- FWIMDataPtr pFWIMData)
- {
- DCLCommandPtr pDCLCommand;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- OHCIRegistersPtr pOHCIRegs;
- UInt32 interruptStatus, interruptStatusLittleEndian;
- UInt32 interruptDCLIndex;
- UInt32 portNum;
- OSStatus status = noErr;
-
- // Get our register base address.
- pOHCIRegs = pFWIMData->pOHCIRegisters;
-
- // Read separate isoch receive interrupt status register to determine context that
- // interrupt is for. intEventClear reads the masked version of interrupt status
- // intEventSet reads the interrupt status without mask. Not used.
- interruptStatusLittleEndian = pOHCIRegs->isochTxIntEventClear;
- interruptStatus = EndianSwapImm32Bit(interruptStatusLittleEndian);
-
- portNum = kIsochTransmitPort;
-
- // scan DCL interrupt list looking for DCL's that have completed
- for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
- {
- pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- if (pDCLCompilerDCLData->pDMA->descriptorField[3])
- pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = true;
- }
-
- if (!pFWIMData->isochTransmitDTScheduled)
- {
- status = FWScheduleDeferredTask(pFWIMData->isochTransmitDeferredTaskID, nil);
-
- if (status == noErr)
- pFWIMData->isochTransmitDTScheduled = true;
- }
-
- pOHCIRegs->isochTxIntEventClear = interruptStatusLittleEndian;
- SynchronizeIO();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // IsochReceiveDeferredTask
- //
- // Handle DMA interrupts for isochronous receive.
- //
-
- void IsochReceiveDeferredTask(
- void *p1,
- void *p2)
- {
- FWIMDataPtr pFWIMData = (FWIMDataPtr) p1;
- OHCIRegistersPtr pOHCIRegs = pFWIMData->pOHCIRegisters;
- IsochPortDataPtr pIsochPortData;
- DCLCommandPtr pDCLCommand;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCallProcPtr pDCLCallProc;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 interruptDCLIndex;
- UInt32 portNum;
- OSStatus status = noErr;
-
- // Isoch receive DT no longer scheduled.
- pFWIMData->isochReceiveDTScheduled = false;
-
- if (pOHCIRegs->isochRxContext[kIRContext0].controlSet & EndianSwapImm32Bit(kDMADead))
- {
- status = -1;
- sprintf(debugStr, "IR context dead, status = 0x%08lx", EndianSwap32Bit(pOHCIRegs->isochRxContext[kIRContext0].controlSet));
- FWDebugStr((ConstStr255Param) c2pstr(debugStr));
- }
-
- if (status == noErr)
- {
- // Get isoch port data.
- // JKL *** need to be able to get portNum when using multiple contexts
- portNum = kIsochReceivePort;
- pIsochPortData = pFWIMData->isochPortDataList[portNum];
-
- // Run through DCL interrupt list looking for DCL's that need processing.
- for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
- {
- if (pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt)
- {
- pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = false;
- pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc(pIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- DCLCompilerUpdateNotification(pIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
-
- // clear xfer status field to note interrupt handled
- // JKL *** OK to clear resCount field here?
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- pDCLCompilerDCLData->pDMA->descriptorField[3] = 0;
- }
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // IsochTransmitDeferredTask
- //
- // Handle DMA interrupts for isochronous transmit.
- //
-
- void IsochTransmitDeferredTask(
- void *p1,
- void *p2)
- {
- FWIMDataPtr pFWIMData = (FWIMDataPtr) p1;
- IsochPortDataPtr pIsochPortData;
- DCLCommandPtr pDCLCommand;
- DCLCompilerDCLDataPtr pDCLCompilerDCLData;
- DCLCallProcPtr pDCLCallProc;
- DCLTimeStampPtr pDCLTimeStamp;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 interruptDCLIndex;
- UInt32 portNum;
- OSStatus status = noErr;
-
- // Isoch transmit DT no longer scheduled.
- pFWIMData->isochTransmitDTScheduled = false;
-
- // Get isoch port data.
- // JKL *** need to be able to get portNum when using multiple contexts
- portNum = kIsochTransmitPort;
- pIsochPortData = pFWIMData->isochPortDataList[portNum];
-
- for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
- {
- if (pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt)
- {
- pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = false;
- pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc(pIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLTimeStampOp :
- // Update the time stamp.
- pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
- UpdateDCLTimeStamp(pDCLTimeStamp);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- DCLCompilerUpdateNotification(pIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
-
- // clear xfer status field to note interrupt handled
- pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- pDCLCompilerDCLData->pDMA->descriptorField[3] = 0;
- }
- }
- }
-